package pers.jsan.litheopen.security.oauth.controller;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;
import pers.jsan.litheopen.security.exception.LitheAuthenticationException;
import pers.jsan.litheopen.security.oauth.UserContextHolder;
import pers.jsan.litheopen.security.oauth.model.LitheAuthenticationToken;
import pers.jsan.litheopen.security.oauth.model.UserDetail;
import pers.jsan.litheopen.security.prover.AuthenticationManager;
import pers.jsan.litheopen.utils.CodeEnum;
import pers.jsan.litheopen.utils.RandomCode;
import pers.jsan.litheopen.utils.Result;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Controller
public class UserOauthController {

    private final static String SESSION = "SESSION";

    @Autowired
    private AuthenticationManager authenticationManager;

    /**
     * 登录接口
     * @param userDetail 用户登录信息
     * @param request
     * @param response
     * @return Result
     */
    @PostMapping("login")
    @ResponseBody
    public Result login(@RequestBody UserDetail userDetail, HttpServletRequest request, HttpServletResponse response) {
        //校验账号密码
        LitheAuthenticationToken litheAuthenticationToken = null;
        try {
            litheAuthenticationToken = authenticationManager.authenticate(new LitheAuthenticationToken(userDetail.getLoginName(), userDetail.getPassword()));
        } catch (LitheAuthenticationException e) {
            e.printStackTrace();
            return new Result(CodeEnum.AUTHENTICATION_ERROR.get(), null, e.getMessage());
        }
        //缓存用户信息
        String token = authenticationManager.cacheLitheAuthenticationToken(litheAuthenticationToken);
        //返回token给过滤处理SESSION
        authenticationManager.cacheSession(token, (String) request.getAttribute(SESSION));
        //返回结果，重定向
        return new Result(CodeEnum.SUCCESS.get(), null, "登录成功");
    }

    /**
     * 授权链接
     * @param response_type 授权类型
     * @param client_id 申请授权应用
     * @param redirect_uri 授权成功重定向链接
     * @param request
     * @param response
     * @return Result
     */
    @GetMapping("oauth/authorize")
    public String authorize(String response_type, String client_id, String redirect_uri, HttpServletRequest request, HttpServletResponse response) {
        String session = (String) request.getAttribute(SESSION);
        String token = authenticationManager.getTokenBySession(session);
        if(StringUtils.isEmpty(token)) {
            String webPath = authenticationManager.getWebPath();
            if(StringUtils.isEmpty(webPath)) {
                webPath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort();
            }
            return "redirect:" + webPath + authenticationManager.getLoginPage() + "?response_type=code&client_id=" + client_id + "&redirect_uri=" + redirect_uri;
        }
        return "redirect:" + redirect_uri + "?code=" + createCode(client_id, token);
    }

    /**
     * 生成临时授权码
     * @param client_id 关联的应用id
     * @param token 凭证
     * @return String
     */
    private String createCode(String client_id, String token) {
        String code = RandomCode.randomString(6);
        authenticationManager.cacheCode(code, client_id, token);
        return code;
    }

    /**
     * 根据临时授权码获取token
     * @param jsonObject
     * @return
     */
    @PostMapping("oauth/getToken")
    @ResponseBody
    public Result getToken(@RequestBody JSONObject jsonObject) {
        String code = jsonObject.getString("code");
        String clientId = jsonObject.getString("clientId");
        String token = authenticationManager.getTokenByCode(code, clientId);
        if(StringUtils.isNotEmpty(token)) {
            authenticationManager.invalidCode(code, clientId);
            return Result.ok(token);
        }
        return new Result(CodeEnum.AUTHENTICATION_ERROR.get(), null, "授权码无效");
    }


    @PostMapping("oauth/getUser")
    @ResponseBody
    public Result getUser() {
        return Result.ok(authenticationManager.formatOauthUserMessage(UserContextHolder.get().getUserDetail()));
    }
}
